package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/e421083458/gorm"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"github.com/gogf/gf/util/gconv"
	"rock/customer/dto"
	"rock/customer/initParam"
	"rock/customer/models"
	"rock/customer/modules/mapping"
	"rock/customer/modules/redisModules"
	"rock/customer/public"
	"time"
)

type Message struct {
}

// 消息 - 列表
func (m *Message) MessagesList(tx *gorm.DB, uid string, search string, pageNum int, pageSize int) (data []dto.ChatMessagePage, count int, err error) {
	// 查缓存
	if search == "" && pageNum == 0 && pageSize == 0 {
		val := ""
		//messagesList_127317
		redisCache := redisModules.ClientRedis.Get(initParam.MessageListPrefix + uid)
		val, err = redisCache.Result()
		if err == nil {
			err = json.Unmarshal([]byte(val), &data)
			if err != nil {
				count = 0
				return
			}
			count = len(data)
			return
		} else {
			if err != redis.Nil {
				return data, 0, err
			}
		}
	}
	//whereGroup := " AND gcm.status <> 5 "
	whereGroup := ""
	wherePrivate := ""
	if search != "" {
		//whereGroup = fmt.Sprintf(" AND ( gcm.content LIKE '%s' OR g.name LIKE '%s') ", "%"+search+"%", "%"+search+"%")
		//wherePrivate = fmt.Sprintf(" AND ( gcm.content LIKE '%s' OR cs.nickname LIKE '%s') ", "%"+search+"%", "%"+search+"%")
		whereGroup = fmt.Sprintf(" AND ( g.name LIKE '%s') ", "%"+search+"%")
		wherePrivate = fmt.Sprintf(" AND ( cs.nickname LIKE '%s') ", "%"+search+"%")
	}
	q := `( (SELECT
				g.group_id,if(ud.realname is NULL,ud.nickname,ud.realname) AS group_name,cs.nickname AS user_name,'%s' AS avatar,g.state,
				DATE_FORMAT(g.last_chat_time,'%s') AS create_time,g.last_object_name AS object_name,g.last_chat_id,g.last_content_text AS content_text,
				g.user_id,g.other_user_id,g.group_type AS chat_type,g.last_from_user_id AS from_user_id,0 as memberType
			FROM
				wkb_im_group g 
				INNER JOIN wkb_user_detail ud ON g.user_id = ud.uid OR g.other_user_id = ud.uid
				INNER JOIN wkb_im_customer_service cs ON cs.uid = ud.uid AND cs.deleted = 2
			WHERE
				( g.user_id = %s OR g.other_user_id = %s )
				AND g.group_type = 2 AND ( (g.other_user_id = 0 ) OR ( ud.uid <> %s AND g.other_user_id > 0 ))  %s
			)
			UNION(
				SELECT
					g.group_id,g.name AS group_name,"" AS user_name,'%s' AS avatar,g.state,
					DATE_FORMAT(g.last_chat_time,'%s') AS create_time,g.last_object_name AS object_name,g.last_chat_id,g.last_content_text AS content_text,
					g.user_id,g.other_user_id,g.group_type AS chat_type,g.last_from_user_id AS from_user_id,gm.member_type as memberType
				FROM
					wkb_im_group g
					INNER JOIN wkb_im_group_member gm ON gm.group_id = g.group_id
				WHERE
					((
						gm.user_id = %s
						AND g.group_type = 1
						AND g.user_id <> %s
					)
					OR (
						gm.user_id = %s
						AND g.group_type = 1
						AND gm.member_type = 2
					))
					%s
			) )ORDER BY state ASC,last_chat_id DESC`
	//gm.user_id = %s AND g.group_type = 1 AND g.user_id <> %s %s
	SQL := fmt.Sprintf(q, initParam.FAEAvatar, "%Y-%m-%d %H:%i:%s", uid, uid, uid, wherePrivate, initParam.FAEAvatar, "%Y-%m-%d %H:%i:%s", uid, uid, uid, whereGroup)
	fmt.Println(fmt.Sprintf("SQL ==> %v ", SQL))
	data, err = rawQueryAllField(tx.DB(), SQL)
	if err != nil {
		if err.Error() != gorm.ErrRecordNotFound.Error() {
			err = errors.New(initParam.DataIsNotExist)
			return
		}
		return
	}
	count = len(data)
	//
	if search == "" && pageNum == 0 && pageSize == 0 {
		err = addRedis(data, initParam.MessageListPrefix + uid, 1*24*time.Hour)
		if err != nil {
			count = 0
			return data, len(data), err
		}
	}
	return
}

// 消息 - 内容
func (m *Message) MessageContent(gc *gin.Context, tx *gorm.DB, pageNum int, pageSize int, groupId string, currentStatus int, id int) (MessageContent []dto.MessageContentInside, count int, err error) {
	where := " AND gcm.status <> 5 "
	err = tx.SetCtx(public.GetGinTraceContext(gc)).
		Model(&models.WkbGroupChatMessage{}).
		Table("wkb_im_group_chat_message gcm").Where("gcm.group_id = ?"+where, groupId).Count(&count).Error
	if count == 0 {
		return
	}
	if currentStatus == 1 {
		where = where + " AND gcm.current_status = 1 AND gcm.content <> '" + initParam.TimeBlockMsg + "' "
	}
	if id != 0 {
		where = where + " AND gcm.id < " + gconv.String(id)
		err = tx.SetCtx(public.GetGinTraceContext(gc)).
			Model(&models.WkbGroupChatMessage{}).
			Table("wkb_im_group_chat_message gcm").
			Select(fmt.Sprintf("gcm.object_name AS message_type,gcm.content_text AS content_struct,gcm.from_user_id AS sender_user_id,"+
				"gcm.to_user_id AS target_id,gcm.msg_timestamp AS sent_time,gcm.msg_timestamp AS received_time,gcm.msg_uid AS message_uid,"+
				"gcm.hidden_user_id,gcm.current_status")).
			//Where("gcm.group_id = ? "+fmt.Sprintf(" and hidden_user_id not like %v ","'%"+userId+"%'"), groupId).
			Where("gcm.group_id = ? "+where, groupId).
			Order("gcm.id DESC").
			Limit(pageSize).
			Scan(&MessageContent).Error
	} else {
		err = tx.SetCtx(public.GetGinTraceContext(gc)).
			Model(&models.WkbGroupChatMessage{}).
			Table("wkb_im_group_chat_message gcm").
			Select(fmt.Sprintf("gcm.object_name AS message_type,gcm.content_text AS content_struct,gcm.from_user_id AS sender_user_id,"+
				"gcm.to_user_id AS target_id,gcm.msg_timestamp AS sent_time,gcm.msg_timestamp AS received_time,gcm.msg_uid AS message_uid,"+
				"gcm.hidden_user_id,gcm.current_status")).
			//Where("gcm.group_id = ? "+fmt.Sprintf(" and hidden_user_id not like %v ","'%"+userId+"%'"), groupId).
			Where("gcm.group_id = ? "+where, groupId).
			Order("gcm.id DESC").
			Limit(pageSize).Offset((pageNum - 1) * pageSize).
			Scan(&MessageContent).Error
	}
	//优化方案，修改sql
	//err = tx.SetCtx(public.GetGinTraceContext(gc)).
	//		Model(&models.WkbGroupChatMessage{}).
	//		Table("wkb_im_group_chat_message gcm").
	//		Select(fmt.Sprintf("gcm.object_name AS message_type,gcm.content_text AS content_struct,gcm.from_user_id AS sender_user_id,"+
	//			"gcm.to_user_id AS target_id,gcm.msg_timestamp AS sent_time,gcm.msg_timestamp AS received_time,gcm.msg_uid AS message_uid,gcm.content," +
	//			"gcm.channel_type as chat_type,gcm.imageUri,gcm.h,gcm.w,gcm.remoteUrl,gcm.duration,gcm.fileUrl,gcm.`name`,gcm.size,gcm.types as type")).
	//		Where("gcm.group_id = ?", groupId).
	//		Order("gcm.id DESC").
	//		Limit(pageSize).Offset((pageNum - 1) * pageSize).
	//		Scan(&MessageContent).Error
	return
}

// 消息 - 插入
func (m *Message) CreateMessage(gc *gin.Context, tx *gorm.DB, groupChatMessage *models.WkbGroupChatMessage) (int, time.Time, error) {
	cr := tx.SetCtx(public.GetGinTraceContext(gc)).Create(groupChatMessage)
	return groupChatMessage.ID, groupChatMessage.CreatedAt, cr.Error
}

// 消息 - 查找消息
func (m *Message) MessageByUid(gc *gin.Context, tx *gorm.DB, msgUid string) (data models.WkbGroupChatMessage, err error) {
	//
	redisCache := redisModules.ClientRedis.Get(initParam.MessagePrefix + msgUid)
	val, err := redisCache.Result()
	if err == nil {
		err = json.Unmarshal([]byte(val), &data)
		if err != nil {
			return
		}
		return
	} else {
		if err != redis.Nil {
			return
		}
	}
	//
	err = tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).Where("msg_uid = ?", msgUid).Scan(&data).Error
	if err != nil {
		return
	}
	if data.MsgUId == "" {
		err = errors.New(initParam.DataIsNotExist)
		return
	}
	// 存缓存
	err = addRedis(data, initParam.MessagePrefix + msgUid, 1*time.Hour)
	return
}

// 消息 - 查找第一条消息
func (m *Message) MessageByGroupId(gc *gin.Context, tx *gorm.DB, groupId string) (msg models.WkbGroupChatMessage, err error) {
	err = tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).Where("group_id = ?", groupId).First(&msg).Error
	return
}

// 消息 - 客户最后消息
func (m *Message) CMessageLast(gc *gin.Context, tx *gorm.DB, groupId string, userId string) (msg dto.ChatMessagePage, err error) {
	err = tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).
		Table("wkb_im_group_chat_message gcm").
		Select(fmt.Sprintf("g.group_id,g.name AS group_name,'' AS user_name,'%s' AS avatar,g.state,"+
			"DATE_FORMAT(g.last_chat_time,'%s') AS create_time,gcm.object_name,g.last_chat_id,gcm.content_text,g.user_id,"+
			"g.other_user_id,g.group_type AS chat_type,gcm.status,gcm.from_user_id,gm.member_type", initParam.FAEAvatar, "%Y-%m-%d %H:%i:%s")).
		Joins("INNER JOIN wkb_im_group g ON g.group_id = gcm.group_id").
		Joins("INNER JOIN wkb_im_group_member gm ON gm.group_id = g.group_id and gm.user_id = ?", userId).
		Where("gcm.group_id = ? AND gcm.object_name <> 'RC:InfoNtf' ", groupId).
		Order("gcm.id DESC").First(&msg).Error
	return
}

// 消息 - 客服最后消息
func (m *Message) CsMessageLast(tx *gorm.DB, groupId string, userId string) (msg dto.ChatMessagePage, err error) {
	SQL := fmt.Sprintf(`SELECT
				g.group_id,g. NAME AS group_name,cs.nickname AS user_name,'%s' AS avatar,
				g.state,DATE_FORMAT(g.last_chat_time,'%s') AS create_time,gcm.object_name,
				g.last_chat_id,gcm.content_text,g.user_id,g.other_user_id,g.group_type AS chat_type,
				gcm.status,gcm.from_user_id,0 AS member_type
			FROM
				wkb_im_group_chat_message gcm
			INNER JOIN wkb_im_group g ON g.group_id = gcm.group_id
			INNER JOIN wkb_im_customer_service cs ON (gcs.uid = g.user_id OR cs.uid = g.other_user_id) AND cs.uid <> %s
			WHERE
				gcm.group_id = '%s' AND gcm.hidden_user_id NOT LIKE '%s'
			ORDER BY gcm.id DESC LIMIT 1`, initParam.FAEAvatar, "%Y-%m-%d %H:%i:%s", userId, groupId, "%"+userId+"%")
	fmt.Println(fmt.Sprintf("SQL ==> %v ", SQL))
	//查询数据，取所有字段
	rows2, _ := tx.DB().Query(SQL)
	//返回所有列
	cols, _ := rows2.Columns()
	//这里表示一行所有列的值，用[]byte表示
	vals := make([][]byte, len(cols))
	//这里表示一行填充数据
	scans := make([]interface{}, len(cols))
	//这里scans引用vals，把数据填充到[]byte里
	for k := range vals {
		scans[k] = &vals[k]
	}
	i := 0
	result := dto.ChatMessagePage{}
	//result := make(map[int]map[string]string, 0)
	for rows2.Next() {
		//填充数据
		_ = rows2.Scan(scans...)
		//每行数据
		//row := dto.ChatMessagePage{}
		row := make(map[string]interface{}, 0)
		//把vals中的数据复制到row中
		//fmt.Println(reflect.TypeOf(vals))
		for k, v := range vals {
			key := cols[k]
			//这里把[]byte数据转成string
			row[key] = string(v)
		}
		d := &dto.ChatMessagePage{}
		err := mapping.SlStruct(row, d, 1)
		if err != nil {
			return result, err
		}
		result = *d
		i++
	}
	defer func() {
		_ = rows2.Close()
	}()
	return result, nil
}

// 消息 - 邀请消息
func (m *Message) MessagesInvitation(gc *gin.Context, tx *gorm.DB, msgUid string) (ChatMessage dto.ChatMessagePage, err error) {
	err = tx.SetCtx(public.GetGinTraceContext(gc)).
		Model(&models.WkbGroupChatMessage{}).
		Table("wkb_im_group_chat_message gcm").
		Select(fmt.Sprintf("wg.group_id,wg.name as name,'%s' AS avatar,wg.state,DATE_FORMAT(gcm.created_at,'%s') as create_time,"+
			"gcm.content_text,wg.user_id,wg.other_user_id,wg.group_type as chat_type,gcm.status", initParam.FAEAvatar, "%Y-%m-%d %H:%i:%s")).
		Joins("INNER JOIN wkb_im_group wg ON wg.group_id = gcm.group_id").
		Where("gcm.msg_uid = ?", msgUid).
		First(&ChatMessage).Error
	return
}

// 消息 - 更新消息状态
func (m *Message) UpdateMessageStatus(gc *gin.Context, tx *gorm.DB, msgUid string, extraMsg string, status int) error {
	return tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).
		Where("msg_uid = ? and extra_msg = ?", msgUid, extraMsg).Update("status", status).Error
}

// 消息 - 更新消息隐藏状态
func (m *Message) UpdateMessageHiddenUserId(gc *gin.Context, tx *gorm.DB, msgUid string, hiddenUserId string) error {
	return tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).
		Where("msg_uid = ?", msgUid).Update("hidden_user_id", hiddenUserId).Error
}

// 消息 - 更新消息当前状态
func (m *Message) UpdateMessageCurrentStatus(gc *gin.Context, tx *gorm.DB, groupId string) error {
	if groupId == "" {
		return tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).
			Where("current_status = 1").Update("current_status", 0).Error
	} else {
		return tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).
			Where("group_id = ? and current_status = 1", groupId).Update("current_status", 0).Error
	}
}

// 消息 - 删除旧时间段
func (m *Message) DeleteMessageTimeBlock(gc *gin.Context, tx *gorm.DB, groupId string) error {
	return tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbGroupChatMessage{}).
		Where("group_id = ? and content = ?", groupId, initParam.TimeBlockMsg).Update("status", 5).Error
}

// 合并消息 - 插入
func (m *Message) CreateMergeMessage(gc *gin.Context, tx *gorm.DB, message *models.WkbImMergeMessage) error {
	return tx.SetCtx(public.GetGinTraceContext(gc)).Model(&models.WkbImMergeMessage{}).Create(message).Error
}

// 合并消息
func (m *Message) MergeMessage(gc *gin.Context, tx *gorm.DB, id string) (mergeMessage models.WkbImMergeMessage, err error) {
	err = tx.SetCtx(public.GetGinTraceContext(gc)).
		Model(&models.WkbImMergeMessage{}).
		Select("merge_id,content").
		Where("merge_id = ?", id).
		Scan(&mergeMessage).Error
	return
}
